package com.lechi.web.server.handle;

import com.alibaba.fastjson2.JSON;
import com.lechi.web.common.utils.bean.BeanUtils;
import com.lechi.web.constants.Constants;
import com.lechi.web.framework.util.GuavaCacheUtil;
import com.lechi.web.framework.websocket.WebSocketServer;
import com.lechi.web.framework.websocket.WebSocketUtil;
import com.lechi.web.system.domain.IotMonitorDataBo;
import com.lechi.web.system.domain.IotWeatherDeviceBo;
import com.lechi.web.system.domain.IotWeatherSensorParseBo;
import com.lechi.web.util.RecordFileUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.util.*;

/**
 * 二代站报文接收
 */
@Slf4j
@Sharable
public final class Weather2017InboundMessageHandler extends SimpleChannelInboundHandler<ByteBuf> implements BaseWeatherInboundHandle {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) {
        String hostName = getHostName(ctx);
        String receiveMessage = byteBuf.toString(Charset.defaultCharset());
        String[] sensorAndStateData = receiveMessage.split(",");
        log.error("WEATHER-2017设备地址： {} ，开始解析报文：{}", hostName, receiveMessage);
        if (!getKeysByValue(hostName).isEmpty()) {
            getKeysByValue(hostName).forEach(deviceId -> WebSocketServer.sendInfo(deviceId + 1000, JSON.toJSONString(Map.of("response", receiveMessage))));
        }
        if (receiveMessage.startsWith("BG") && !checkEquals(receiveMessage)) {
            return;
        }
        List<IotWeatherDeviceBo> weatherDeviceBoList = (List<IotWeatherDeviceBo>) GuavaCacheUtil.getCmdParseTableMap().getOrDefault(Constants.WEATHER2017, new ArrayList<>());
        String deviceStation = null;
        int watchDataBeginIndex = 0;
        String qualityStr = null;
        Date watchTime = null;
        String watchArea = "";
        boolean deviceSignBool = false;
        boolean instrumentIdBool = false;
        boolean stationNumBool = false;
        for (IotWeatherDeviceBo iotWeatherDeviceBo : weatherDeviceBoList) {
            deviceSignBool = Objects.equals(iotWeatherDeviceBo.getDeviceSign(), sensorAndStateData[iotWeatherDeviceBo.getDeviceSignIndex()]);
            instrumentIdBool = Objects.equals(iotWeatherDeviceBo.getInstrumentId(), sensorAndStateData[iotWeatherDeviceBo.getInstrumentIndex()]);
            stationNumBool = Objects.equals(iotWeatherDeviceBo.getDeviceStation(), sensorAndStateData[iotWeatherDeviceBo.getStationNumIndex()]);
            if (deviceSignBool && instrumentIdBool && stationNumBool) {
                deviceStation = iotWeatherDeviceBo.getDeviceStation();
                GuavaCacheUtil.getDeviceLastDated().put(iotWeatherDeviceBo.getDeviceId().toString(), new Date());
                GuavaCacheUtil.getDeviceIdAndIPMap().put(iotWeatherDeviceBo.getDeviceId(), hostName);
                watchDataBeginIndex = iotWeatherDeviceBo.getWatchDataIndex();
                qualityStr = sensorAndStateData[watchDataBeginIndex + Integer.parseInt(sensorAndStateData[iotWeatherDeviceBo.getSensorNumIndex()]) * 2];
                watchTime = Optional.ofNullable(sensorAndStateData[iotWeatherDeviceBo.getDateTimeIndex()]).map(this::parseStrToDate).orElse(null);
                watchArea = Optional.ofNullable(sensorAndStateData[iotWeatherDeviceBo.getDateTimeIndex() - 1]).orElse("");
                break;
            }
        }
        String[] qualityCode = qualityStr.split("");
        Map<String, IotWeatherSensorParseBo> sensorParseBoMap = GuavaCacheUtil.getWeatherParseTableMap().getOrDefault(deviceStation, new HashMap<>());
        List<IotMonitorDataBo> weather2017DeviceDataList = new ArrayList<>();
        int step = 2;
        int qualityCodeIndex = 0;
        for (int i = watchDataBeginIndex, length = sensorAndStateData.length; i < length - step; i = i + step) {
            if ("/".equals((sensorAndStateData[i + 1])) || qualityStr.equals(sensorAndStateData[i])) {
                step = 1;
                continue;
            } else {
                step = 2;
            }
            if (sensorParseBoMap.containsKey(sensorAndStateData[i].trim())) {
                IotWeatherSensorParseBo sensorParseBo = sensorParseBoMap.get(sensorAndStateData[i].trim());
                IotMonitorDataBo iotMonitorPageData = new IotMonitorDataBo();
                BeanUtils.copyProperties(sensorParseBo, iotMonitorPageData);
                String doubleValue = Optional.ofNullable(sensorAndStateData[i + 1]).orElse("");
                if ("string".equals(sensorParseBo.getValueType())) {
                    iotMonitorPageData.setDoubleValue(doubleValue).setStringValue(doubleValue).setDateTime(watchTime);
                } else {
                    try {
                        var v = Double.parseDouble(doubleValue) * Optional.ofNullable(sensorParseBo.getIntFactor()).orElse(1d);
                        String format = new DecimalFormat(Optional.ofNullable(sensorParseBo.getSensorDigit()).filter(n -> n > 0).map(n -> "0." + "0".repeat(n)).orElse("0")).format(v);
                        iotMonitorPageData.setValue(Float.parseFloat(format)).setStringValue(format).setDoubleValue(format).setDateTime(watchTime);
                    } catch (NumberFormatException e) {
                        log.error("WEATHER-2017解析报文NumberFormatException异常：{}", receiveMessage);
                        continue;
                    }
                }
                if (qualityCodeIndex < qualityCode.length) {
                    try {
                        iotMonitorPageData.setQualityCode(qualityCode[qualityCodeIndex]);
                        qualityCodeIndex++;
                    } catch (Exception e) {
                        log.error("WEATHER-2017 Invalid quality code: {}", qualityCode[qualityCodeIndex], e);
                    }
                }
                IotMonitorDataBo iotMonitorDataBo = GuavaCacheUtil.getMonitorDataMap().get(iotMonitorPageData.getDeviceId(), iotMonitorPageData.getSensorAliasId());
                weather2017DeviceDataList.add(iotMonitorPageData);
                if (iotMonitorDataBo == null || (iotMonitorDataBo.getDateTime() != null && watchTime.after(iotMonitorDataBo.getDateTime()))) {
                    alarmRuleChain(iotMonitorPageData);
                    WebSocketUtil.sendToMonitorPage(iotMonitorPageData);
                    GuavaCacheUtil.getMonitorDataMap().put(iotMonitorPageData.getDeviceId(), iotMonitorPageData.getSensorAliasId(), iotMonitorPageData);
                }
                insertData(iotMonitorPageData);
            }
        }
        WebSocketUtil.sendToDevicePage(Constants.WEATHER2017, weather2017DeviceDataList, receiveMessage);
        if (!receiveMessage.contains("RAW")) {
            RecordFileUtil.producerRecord(weather2017DeviceDataList, receiveMessage, watchArea);
        }
        RecordFileUtil.producerRecordCsv(weather2017DeviceDataList);
    }
}
